package com.my.test.thread.ThreadLocal;


/**
 * ThreadLocal：线程的本地变量，它将自己作为key将set的值作为value，存储到当前线程的ThreadLocalMap里
 * 也就是说一个线程可以通过ThreadLocal，查询绑定到这个线程上的一个值在多线程环境下防止自己的变量被其他线
 * 程修改
 * hibernate的session每个线程访问数据库都应当是一个独立的Session会话，如果多个线程共享同一个Session会话，
 * 有可能其他线程关闭连接了，
 * 当前线程再执行提交时就会出现会话已关闭的异常，导致系统异常。此方式能避免线程争抢Session，提高并发下的安全性。
 * 使用ThreadLocal的典型场景正如上面的数据库连接管理，线程会话管理等场景，
 *

 * 如何避免泄漏
 * 既然Key是弱引用，那么我们要做的事，就是在调用ThreadLocal的get()、set()方法时完成后再调用remove方法，将Entry
 * 节点和Map的引用关系移除，这样整个Entry对象在GC Roots分析后就变成不可达了，下次GC的时候就可以被回收。
 *
 * 线性探测初始化ThreadLocal时候hash值就增加一个固定的HASH_INCREMENT(0x61c88647)大小,HashMap采用链表法
 * 线性探测法根据初始key的hashcode值确定元素在table数组中的位置，如果发现这个位置上已经有其他key值的元素被占用，
 * 则利用固定的算法寻找一定步长的下个位置，依次判断，直至找到能够存放的位置。 弱引用，生命周期只能存活到下次GC前
 */

public class Test extends Thread{
    // hash冲突解决这样的场景 local、local2
    private static ThreadLocal<Integer> local = new ThreadLocal<>();

    private static ThreadLocal<Integer> local2 = new ThreadLocal<>();

    // 每个线程都有一个属于自己的 ThreadLocals(ThreadLocal.ThreadLocalMap)
    // 所以会隔离线程数据
    public static void main(String[] args) throws InterruptedException {
        // 存在main线程的ThreadLocals(ThreadLocal.ThreadLocalMap)中

        try {
            local.set(1);
        } finally {
            Thread.sleep(3000);
            local.remove();
        }
        System.out.println(local.hashCode());
        System.out.println(local2.hashCode());
        new Test().start();
    }

    @Override
    public void run (){
        //从Test这个线程的ThreadLocals(ThreadLocal.ThreadLocalMap)中获取
        System.out.println(local.get());  // null

        int n = 0;
        int sizeCtl = 5;
        if ((n = sizeCtl)<0){ // 赋值和判断操作在一起
            System.out.println(sizeCtl);
        }else{
            System.out.println(n);
        }
    }


}
